분류 문제는 회귀 분석과 달리 모수에 대한 t-검정, 신뢰 구간(confidence interval) 추정 등이 쉽지 않기 때문에 이를 보완하기 위해 다양한 성능 평가 기준이 필요하다.
sklearn.metrics
서브 패키지confusion_matrix()
classfication_report()
accuracy_score(y_true, y_pred)
precision_score(y_true, y_pred)
recall_score(y_true, y_pred)
fbeta_score(y_true, y_pred, beta)
f1_score(y_true, y_pred)
분류 결과표는 타겟의 원래 클래스와 모형이 예측한 클래스가 일치하는지는 갯수로 센 결과이다.
원래 클래스는 행(row)으로 예측한 클래스는 열(column)로 나타낸다.
예측 클래스 0 | 예측 클래스 1 | 예측 클래스 2 | |
---|---|---|---|
원 클래스 0 | 원 클래스가 0, 예측 클래스가 0인 표본의 수 | 원 클래스가 0, 예측 클래스가 1인 표본의 수 | 원 클래스가 0, 예측 클래스가 2인 표본의 수 |
원 클래스 1 | 원 클래스가 1, 예측 클래스가 0인 표본의 수 | 원 클래스가 1, 예측 클래스가 1인 표본의 수 | 원 클래스가 1, 예측 클래스가 2인 표본의 수 |
원 클래스 2 | 원 클래스가 2, 예측 클래스가 0인 표본의 수 | 원 클래스가 2, 예측 클래스가 1인 표본의 수 | 원 클래스가 2, 예측 클래스가 2인 표본의 수 |
In [1]:
from sklearn.metrics import confusion_matrix
In [2]:
y_true = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]
confusion_matrix(y_true, y_pred)
Out[2]:
In [3]:
y_true = ["cat", "ant", "cat", "cat", "ant", "bird"]
y_pred = ["ant", "ant", "cat", "cat", "ant", "cat"]
confusion_matrix(y_true, y_pred, labels=["ant", "bird", "cat"])
Out[3]:
클래스가 0과 1 두 종류 밖에 없는 경우에는 일반적으로 클래스 이름을 "Positive"와 "Negative"로 표시한다.
또, 분류 모형의 예측 결과가 맞은 경우, 즉 Positive를 Positive라고 예측하거나 Negative를 Negative라고 예측한 경우에는 "True"라고 하고 예측 결과가 틀린 경우, 즉 Positive를 Negative라고 예측하거나 Negative를 Positive라고 예측한 경우에는 "False"라고 한다.
이 경우의 이진 분류 결과의 명칭과 결과표는 다음과 같다. 이 표는 외우는 것이 좋다.
Positive라고 예측 | Negative라고 예측 | |
---|---|---|
실제 Positive | True Positive | False Negative |
실제 Negative | False Positive | True Negative |
FDS(Fraud Detection System)는 금융 거래, 회계 장부 등에서 잘못된 거래, 사기 거래를 찾아내는 시스템을 말한다. FDS의 예측 결과가 Positive 이면 사기 거래라고 예측한 것이고 Negative 이면 정상 거래라고 예측한 것이다. 이 결과가 사실과 일치하는지 틀리는지에 따라 다음과 같이 말한다.
사기 거래라고 예측 | 정상 거래라고 예측 | |
---|---|---|
실제로 사기 거래 | True Positive | False Negative |
실제로 정상 거래 | False Positive | True Negative |
In [4]:
#F score
from sklearn.metrics import classification_report
In [5]:
y_true = [0, 1, 2, 2, 2]
y_pred = [0, 0, 2, 2, 1]
target_names = ['class 0', 'class 1', 'class 2']
print(classification_report(y_true, y_pred, target_names=target_names))
In [6]:
y_true = ["cat", "ant", "cat", "cat", "ant", "bird"]
y_pred = ["ant", "ant", "cat", "cat", "ant", "cat"]
print(classification_report(y_true, y_pred, target_names=["ant", "bird", "cat"]))
ROC(Receiver Operator Characteristic) 커브는 클래스 판별 기준값의 변화에 따른 Fall-out과 Recall의 변화를 시각화한 것이다.
모든 이진 분류 모형은 판별 평면으로부터의 거리에 해당하는 판별 함수(discriminant function)를 가지며 판별 함수 값이 음수이면 0인 클래스, 양수이면 1인 클래스에 해당한다고 판별한다. 즉 0 이 클래스 판별 기준값이 된다. ROC 커브는 이 클래스 판별 기준값이 달라진다면 판별 결과가 어떻게 달라지는지는 표현한 것이다.
Scikit-Learn 의 Classification 클래스는 판별 함수 값을 계산하는 decision_function
메서드를 제공한다. ROC 커브는 이 판별 함수 값을 이용하여 다음과 같이 작성한다.
일반적으로 클래스 판별 기준이 변화함에 따라 Recall과 Fall-out은 같이 증가하거나 감소한다. Recall이 크고 Fall-out이 작은 모형은 좋은 모형으로 생각할 수 있다.
In [7]:
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
X, y = make_classification(n_features=1, n_redundant=0, n_informative=1, n_clusters_per_class=1, random_state=4)
model = LogisticRegression().fit(X, y)
In [8]:
print(confusion_matrix(y, model.predict(X)))
In [9]:
print(classification_report(y, model.predict(X)))
In [10]:
from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y, model.decision_function(X))
#decision_function은 값이 크면 클수록 class 1쪽으로 더 많이 들어간 것이고
#무한대로 간 것은 class0으로 더 많이 들어간 것.
In [12]:
plt.plot(fpr, tpr)
plt.plot([0, 1], [0, 1], 'k--', label="random guess")
#random guess 점선은 무능한 경찰의 기준. 일을 열심히 하면 위에, 아니면 아래의 곡선상의 위치
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.title('Receiver operating characteristic example')
plt.show()
In [14]:
tpr
Out[14]:
In [15]:
fpr
Out[15]:
In [17]:
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
iris = load_iris()
model = LogisticRegression().fit(iris.data, iris.target)
In [18]:
from sklearn.metrics import roc_curve
fpr0, tpr0, thresholds0 = roc_curve(iris.target, model.decision_function(iris.data)[:, 0], pos_label=0)
fpr1, tpr1, thresholds1 = roc_curve(iris.target, model.decision_function(iris.data)[:, 1], pos_label=1)
fpr2, tpr2, thresholds2 = roc_curve(iris.target, model.decision_function(iris.data)[:, 2], pos_label=2)
In [19]:
fpr0, tpr0, thresholds0
Out[19]:
thresholds를 줄이면 아래로 늘리면 오른쪽으로
In [20]:
plt.plot(fpr0, tpr0, "r-", label="class 0 ") #빨간선이 가장 좋은선
plt.plot(fpr1, tpr1, "g-", label="class 1")
plt.plot(fpr2, tpr2, "b-", label="class 2")
plt.plot([0, 1], [0, 1], 'k--', label="random guess")
plt.xlim(-0.05, 1.0)
plt.ylim(0, 1.05)
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
In [21]:
print(confusion_matrix(iris.target, model.predict(iris.data)))
In [23]:
print(classification_report(iris.target, model.predict(iris.data)))
In [24]:
from sklearn.preprocessing import label_binarize
yb0 = label_binarize(iris.target, classes=[0, 1, 2])
yb1 = label_binarize(model.predict(iris.data), classes=[0, 1, 2])
In [25]:
print(yb0[:, 0].sum(), yb1[:, 0].sum())
plt.plot(yb0[:, 0], 'ro-', markersize=10, alpha=0.4, label="actual class 0")
plt.plot(yb1[:, 0], 'bs-', markersize=10, alpha=0.4, label="predicted class 0")
plt.legend()
plt.xlim(0, len(iris.target)-1);
plt.ylim(-0.1, 1.1);
In [26]:
print(yb0[:, 1].sum(), yb1[:, 1].sum())
plt.plot(yb0[:, 1], 'ro-', markersize=10, alpha=0.6, label="actual class 1")
plt.plot(yb1[:, 1], 'bs-', markersize=10, alpha=0.6, label="predicted class 1")
plt.legend()
plt.xlim(45, 145);
plt.ylim(-0.1, 1.1);
In [27]:
from sklearn.metrics import auc
auc(fpr0, tpr0), auc(fpr1, tpr1), auc(fpr2, tpr2)
Out[27]:
Precision-Recall 커브는 ROC를 계산하는 것과 동일한 방법으로 판별 기준값의 변화에 따른 Precision과 Recall 의 변화를 살펴보는 것이다.
판별 기준값이 증가하면 Recall은 무조건적으로 증가(또는 동일)하지만 Precision은 감소할 수 있다.
In [28]:
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
X, y = make_classification(n_features=1, n_redundant=0, n_informative=1, n_clusters_per_class=1, weights=[0.9, 0.1], random_state=4)
model = LogisticRegression().fit(X, y)
In [29]:
from sklearn.metrics import precision_recall_curve
pre, rec, thresholds = precision_recall_curve(y, model.decision_function(X))
In [30]:
plt.plot(rec, pre)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')
plt.show()
In [31]:
y.sum(), len(y)
Out[31]:
In [2]:
from sklearn.metrics import confusion_matrix
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
X, y = make_classification(n_features=1, n_redundant=0, n_informative=1, n_clusters_per_class=1, random_state=4)
model = LogisticRegression().fit(X, y)
In [3]:
from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y, model.decision_function(X))
In [4]:
plt.plot(fpr, tpr)
plt.plot([0, 1], [0, 1], 'k--', label="random guess")
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.title('Receiver operating characteristic example')
plt.show()
In [5]:
print(confusion_matrix(y, model.predict(X)))
In [6]:
print(classification_report(y, model.predict(X)))
In [7]:
tpr
Out[7]:
In [8]:
fpr
Out[8]:
In [32]:
v = model.decision_function(X)
In [33]:
v
Out[33]:
In [34]:
plt.plot(v)
Out[34]:
In [35]:
v2 = sorted(v)
In [36]:
v2
Out[36]:
In [37]:
plt.plot(v2)
Out[37]:
In [38]:
v.sort()
plt.plot(v)
Out[38]:
In [39]:
v < 0
Out[39]:
In [40]:
(v < 0).sum()
Out[40]:
In [41]:
idx = (v < 0).sum()
v[idx-1], v[idx]
Out[41]:
In [42]:
thresholds # 값이 변하는 변곡점들을 출력한 결과
Out[42]:
In [43]:
idx = np.sum(thresholds > 0)
idx
Out[43]:
In [44]:
thresholds[idx-1], thresholds[idx]
Out[44]:
In [45]:
tpr[idx-1], tpr[idx]
Out[45]:
In [46]:
fpr[idx-1], fpr[idx]
Out[46]:
In [47]:
idx = (thresholds > 0).sum()
tpr0 = tpr[idx-1:idx+1].mean()
fpr0 = fpr[idx-1:idx+1].mean()
In [48]:
plt.plot(fpr, tpr)
plt.plot([0, 1], [0, 1], 'k--', label="random guess")
plt.plot(fpr0, tpr0, "ro", ms=15, alpha=0.8) #알파값??
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.title('Receiver operating characteristic example')
plt.show()
In [49]:
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
iris = load_iris()
model = LogisticRegression().fit(iris.data, iris.target)
In [50]:
from sklearn.metrics import roc_curve
fpr0, tpr0, thresholds0 = roc_curve(iris.target, model.decision_function(iris.data)[:, 0], pos_label=0)
fpr1, tpr1, thresholds1 = roc_curve(iris.target, model.decision_function(iris.data)[:, 1], pos_label=1)
fpr2, tpr2, thresholds2 = roc_curve(iris.target, model.decision_function(iris.data)[:, 2], pos_label=2)
In [51]:
fpr0, tpr0, thresholds0
Out[51]:
In [52]:
idx0 = (thresholds0 > 0).sum()
tpr01 = tpr[idx0-1:idx0+1].mean()
fpr01 = fpr[idx0-1:idx0+1].mean()
idx1 = (thresholds1 > 0).sum()
tpr11 = tpr[idx1-1:idx1+1].mean()
fpr11 = fpr[idx1-1:idx1+1].mean()
idx2 = (thresholds2 > 0).sum()
tpr21 = tpr[idx2-1:idx2+1].mean()
fpr21 = fpr[idx2-1:idx2+1].mean()
In [53]:
plt.plot(fpr01, tpr01, "ro", ms=12 , alpha=0.8)
plt.plot(fpr11, tpr11, "go", ms=12)
plt.plot(fpr21, tpr21, "bo", ms=12)
plt.plot(fpr0, tpr0, "r-", label="class 0 ")
plt.plot(fpr1, tpr1, "g-", label="class 1")
plt.plot(fpr2, tpr2, "b-", label="class 2")
plt.plot([0, 1], [0, 1], 'k--', label="random guess")
plt.xlim(-0.05, 1.0)
plt.ylim(0, 1.05)
plt.xlabel('False Positive Rate (Fall-Out)')
plt.ylabel('True Positive Rate (Recall)')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
#이거 방법 다시 강구해보기
class1이냐 아니냐의 문제는 잘 안 풀린 문제다. 녹색선
In [ ]: